"""FastAPI 服务器."""

from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

from app.api.routes import router
from app.core.config import ADVERTISE_URL, LISTEN_URL, settings
from app.core.middleware import add_middlewares
from app.utils.logger import get_logger

logger = get_logger(__name__)


def create_app() -> FastAPI:
    """创建 FastAPI 应用实例."""
    app = FastAPI(
        lifespan=lifespan,
        default_response_class=ORJSONResponse,
        title=settings.APP_NAME,
        version=settings.APP_VERSION,
        description=settings.APP_DESCRIPTION,
        openapi_url=settings.OPENAPI_PATH if settings.OPENAPI_ENABLED else None,
        docs_url=settings.OPENAPI_DOCS_PATH if settings.OPENAPI_ENABLED else None,
        redoc_url=settings.OPENAPI_REDOC_PATH if settings.OPENAPI_ENABLED else None,
    )

    # 添加中间件
    add_middlewares(app)

    # 包含 API 路由
    app.include_router(router)

    # 启动 OpenTelemetry
    if settings.OTEL_ENABLED:
        from os import environ

        from opentelemetry.instrumentation.auto_instrumentation import initialize
        from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
        from opentelemetry.sdk.environment_variables import OTEL_SERVICE_NAME

        environ[OTEL_SERVICE_NAME] = settings.APP_NAME

        initialize()
        FastAPIInstrumentor.instrument_app(app)

    return app


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    """应用生命周期管理."""
    # 打印配置信息
    logger.info("📦 配置信息", **settings.model_dump_safe())

    # 打印启动信息
    logger.info(
        "🚀 服务器启动成功",
        listen=LISTEN_URL,
        advertise=ADVERTISE_URL,
    )
    if settings.OPENAPI_ENABLED:
        logger.info(
            "📋 OpenAPI 接口",
            listen=f"{LISTEN_URL}{settings.OPENAPI_PATH}",
            advertise=f"{ADVERTISE_URL}{settings.OPENAPI_PATH}",
        )
        logger.info(
            "📚 Swagger 文档",
            listen=f"{LISTEN_URL}{settings.OPENAPI_DOCS_PATH}",
            advertise=f"{ADVERTISE_URL}{settings.OPENAPI_DOCS_PATH}",
        )
        logger.info(
            "📖 ReDoc 文档",
            listen=f"{LISTEN_URL}{settings.OPENAPI_REDOC_PATH}",
            advertise=f"{ADVERTISE_URL}{settings.OPENAPI_REDOC_PATH}",
        )

    yield

    # 关闭服务器
    logger.info("🛑 正在关闭服务器...")
